﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CodeRepositoryConsole.DesignPattern
{

    /// <summary>
    /// First version - not thread-safe
    /// <seealso cref="http://csharpindepth.com/Articles/General/Singleton.aspx"/>
    /// </summary>
    public class SingletonUnthreadSafe
    {
        private static SingletonUnthreadSafe instance = null;

        private SingletonUnthreadSafe() { }

        public static SingletonUnthreadSafe Instance
        {
            get
            {
                if (instance == null)
                    instance = new SingletonUnthreadSafe();
                return instance;
            }
        }

    }

    /// <summary>
    /// Second version - simple thread-safety
    /// </summary>
    public class SingletonThreadSafe
    {
        private static SingletonThreadSafe instance = null;

        private static readonly object padlock = new object();

        private SingletonThreadSafe() { }

        public static SingletonThreadSafe Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                        instance = new SingletonThreadSafe();
                    return instance;
                }
            }
        }
    }

    // Third version - attempted thread-safety using double-check locking
    // Bad code! Do not use
    public class SingletonDoubleCheck
    {
        private static SingletonDoubleCheck instance = null;
        private static readonly object padlock = new object();

        SingletonDoubleCheck() { }

        public static SingletonDoubleCheck Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (padlock)
                    {
                        if (instance == null)
                        {
                            instance = new SingletonDoubleCheck();
                        }
                    }
                }
                return instance;
            }
        }
    }

    /// <summary>
    /// Fourth version - not quite as lazy, but thread-safe without using locks
    /// </summary>
    public class SingletonStaticCtor
    {
        private static SingletonStaticCtor instance = new SingletonStaticCtor();

        /// <summary>
        /// Explicit static constructor to tell C# compiler
        /// not to make type as beforefieldinit
        /// </summary>
        static SingletonStaticCtor()
        {
        }

        private SingletonStaticCtor() { }

        public SingletonStaticCtor Instance
        {
            get { return instance; }
        }
    }

    /// <summary>
    /// Fifth version - fully lazy instantiation
    /// </summary>
    public class SingletonNestClass
    {
        private SingletonNestClass() { }

        public static SingletonNestClass Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        private class Nested
        {
            /// <summary>
            /// Explicit static constructor to tell C# compiler
            /// not to make type as beforefieldinit
            /// </summary>
            static Nested() { }

            internal static readonly SingletonNestClass instance = new SingletonNestClass();
        }
    }

    /// <summary>
    /// Sixth version - using .Net 4's Lazy<T> type
    /// </summary>
    public class SingletonLazy
    {

        private static Lazy<SingletonLazy> lazy = new Lazy<SingletonLazy>(() => new SingletonLazy());

        public static SingletonLazy Instance
        {
            get { return lazy.Value; }
        }

        private SingletonLazy() { }

    }
}
